home *** CD-ROM | disk | FTP | other *** search
/ EnigmA Amiga Run 1996 February / EnigmA AMIGA RUN 04 (1996)(G.R. Edizioni)(IT)[!][issue 1996-02][Skylink CD III].iso / earcd / program / mkdpnd11.lha / MkDepend-1.1 / main.c < prev    next >
C/C++ Source or Header  |  1995-10-14  |  32KB  |  1,286 lines

  1. /*
  2. $VER: main:c 1.1 (12-Oct-95) Copyright © by Lars Düning
  3. */
  4.  
  5. /*---------------------------------------------------------------------------
  6. ** Main module of MkDepend.
  7. **
  8. ** Copyright © 1995  Lars Düning  -  All rights reserved.
  9. ** Permission granted for non-commercial use.
  10. **---------------------------------------------------------------------------
  11. ** The module implements the argument parsing and the control flow.
  12. **
  13. ** Usage:
  14. **   mkdepend {-i|INCLUDE <includepath>[::<symbol>]}
  15. **            {-x|EXCEPT  <filepattern>}
  16. **            {-s|SUFFIX  <src_ext>{,<src_ext>}[:<obj_ext>] | :<obj_ext>}
  17. **            {-p|OBJPAT  <src_ext>{,<src_ext>}:<obj_pattern>
  18. **            [-f|MAKE    <makefile>]
  19. **            [-v|VERBOSE]
  20. **            {<filepattern>}
  21. **
  22. ** The <objpattern> recognizes as meta-symbols:
  23. **   %s: the full sourcename (w/o suffix)
  24. **   %[-][<][<number>]p: the path part of the sourcename
  25. **     <number>: skip first <number> directories of the path, defaults to 0.
  26. **     <       : directories are counted from the end.
  27. **     -       : use, don't skip the counted directories.
  28. **   %n: the base of the sourcename (w/o suffix)
  29. **   %%: the character %
  30. **   %x: the character 'x' for every other character.
  31. **
  32. **---------------------------------------------------------------------------
  33. ** C: DICE 3.01
  34. **---------------------------------------------------------------------------
  35. ** [lars] Lars Düning; Am Wendenwehr 25; D-38114-Braunschweig;
  36. **                     Germany; Tel. 49-531-345692
  37. **---------------------------------------------------------------------------
  38. ** 11-Sep-95 [lars]
  39. ** 12-Oct-95 [lars] %p expanded to %[-][<][<number>]p
  40. ** 13-Oct-95 [lars] current
  41. **---------------------------------------------------------------------------
  42. */
  43.  
  44. #include <assert.h>
  45. #include <ctype.h>
  46. #include <stdio.h>
  47. #include <stdlib.h>
  48. #include <string.h>
  49. #include <sys/stat.h>
  50.  
  51. #include <dos/dos.h>
  52. #include <dos/rdargs.h>
  53. #include <exec/types.h>
  54. #include <exec/libraries.h>
  55. #include <clib/exec_protos.h>
  56. #include <clib/dos_protos.h>
  57.  
  58. #include "reader.h"
  59. #include "nodes.h"
  60.  
  61. extern struct Library *SysBase;
  62.  
  63. /*-------------------------------------------------------------------------*/
  64.  
  65. /* Release version number, should match the version number in the Makefiles */
  66.  
  67. #define VERSION "1.1"
  68.  
  69. /* Dynamic string array */
  70.  
  71. typedef struct sarray
  72. {
  73.   int     size;   /* Number of used strings */
  74.   int     alloc;  /* Number of allocated string pointers */
  75.   char ** strs;   /* Array of string pointers */
  76. } SArray;
  77.  
  78. /* Program arguments */
  79.  
  80. static short    bVerbose = FALSE;          /* TRUE: Verbose action */
  81. static SArray   aFiles   = { 0, 0, NULL }; /* Source files */
  82. static SArray   aAvoid   = { 0, 0, NULL }; /* Source files to avoid */
  83. static SArray   aIncl    = { 0, 0, NULL }; /* Include paths */
  84. static SArray   aSymbol  = { 0, 0, NULL }; /* Include path symbols */
  85. static SArray   aSrcExt  = { 0, 0, NULL }; /* Source file extensions */
  86. static SArray   aObjExt  = { 0, 0, NULL }; /* Associated object file extensions */
  87. static SArray   aObjPat  = { 0, 0, NULL }; /* Associated object file patterns */
  88. static char   * sObjExt  = NULL;           /* Default object file extension */
  89. static char   * sMake    = NULL;           /* Name of the Makefile */
  90.  
  91. /* Misc Variables */
  92.  
  93. static char * aPgmName = NULL;  /* Name of the program executable */
  94. char * aVersion = "$VER: MkDepend " VERSION " (" __DATE__ ")";
  95.  
  96. static struct stat aMakeStat;    /* Stat buffer for the Makefile */
  97. static int         bMakeExists;  /* TRUE: Old Makefile exists */
  98.  
  99. static int         returncode = RETURN_OK;   /* Global return code */
  100.  
  101. /*-----------------------------------------------------------------------*/
  102. static void
  103. set_rc (int code, int bAbort)
  104.  
  105. /* Set the global returncode to <code> given that <code> is higher
  106.  * than the current one.
  107.  * If <bAbort>, exit immediately then.
  108.  */
  109.  
  110. {
  111.   if (code > returncode)
  112.     returncode = code;
  113.   if (bAbort)
  114.     exit(returncode);
  115. }
  116.  
  117. /*-----------------------------------------------------------------------*/
  118. static int
  119. chmod (char *file, long mode)
  120.  
  121. /* Set the access mode of a file.
  122.  * For Amiga-OS, only the owner access can be set.
  123.  */
  124.  
  125. {
  126.   BPTR lock;
  127.   struct FileInfoBlock *info;
  128.   int rc;
  129.  
  130.   /* Unix mode 'rwx??????' => DOS mode 'rwxw' aka 'rwxd'.
  131.   ** Well, this should be done using the FIB* constants from dos.h
  132.   ** but they will hardly change and 'knowing' them keeps this a one-liner.
  133.   ** Note that the Amiga-OS bits disallow the operation when set.
  134.   */
  135.   mode = ~((mode & 0700) >> 5 | (mode & 0200) >> 7) & 017;
  136.   info = (struct FileInfoBlock *) malloc(sizeof (struct FileInfoBlock));
  137.   if (info == NULL) return -1;
  138.   rc = -1;
  139.   if ((lock = Lock(file, SHARED_LOCK)) == NULL) goto chmod_exit;
  140.   if (Examine(lock, info) == DOSFALSE) goto chmod_exit;
  141.   UnLock(lock);
  142.   if (SetProtection(file, (info->fib_Protection & (~017)) | mode) != DOSFALSE)
  143.     rc = 0;
  144. chmod_exit:
  145.   free (info);
  146.   return rc;
  147. }
  148.  
  149. /*-----------------------------------------------------------------------*/
  150. static void
  151. CheckStacksize (LONG try_size)
  152.  
  153. /* Check the stacksize of this process against try_size.
  154.  * If the actual stacksize is smaller, print a message and exit.
  155.  */
  156.  
  157. {
  158.   struct Task *pThis;
  159.  
  160.   pThis = (struct Task *)FindTask(NULL);
  161.  
  162.   /* Sanity checks, shouldn't happen anyway */
  163.   assert(pThis && pThis->tc_Node.ln_Type == NT_PROCESS);
  164.  
  165.   if ((LONG)((char *)pThis->tc_SPUpper - (char *)pThis->tc_SPLower) < try_size)
  166.   {
  167.     printf("%s: Needs at least %ld KByte stack.\n", aPgmName, (try_size+512) >> 10);
  168.     exit(RETURN_ERROR);
  169.   }
  170. }
  171.  
  172. /*-------------------------------------------------------------------------*/
  173. static void
  174. check_os2 (void)
  175.  
  176. /* Check if OS2 is available. If not, print a message and exit.
  177.  */
  178.  
  179. {
  180.   char *sNeedsOS2 = "Fatal: Needs OS 2.0 or better.\n";
  181.  
  182.   if (SysBase->lib_Version < 36)
  183.   {
  184.     Write(Output(), sNeedsOS2, strlen(sNeedsOS2));
  185.     set_rc(RETURN_FAIL, 1);
  186.   }
  187. }
  188.  
  189. /*-------------------------------------------------------------------------*/
  190. static void
  191. exit_doserr (int code)
  192.  
  193. /* Print a message according to IoErr(), then exit with <code>.
  194.  */
  195.  
  196. {
  197.   PrintFault(IoErr(), aPgmName);
  198.   set_rc(code, 1);
  199. }
  200.  
  201. /*-------------------------------------------------------------------------*/
  202. static void
  203. exit_nomem (int code)
  204.  
  205. /* Print a "Out of Memory" message and exit with <code>.
  206.  */
  207.  
  208. {
  209.   printf("%s: Out of memory.\n", aPgmName);
  210.   set_rc(code, 1);
  211. }
  212.  
  213. /*-------------------------------------------------------------------------*/
  214. static int
  215. array_addfile (SArray *pArray, char * pName)
  216.  
  217. /* Add a copy of <*pName> to the string array <pArray>.
  218.  * Return 0 on success, non-0 on error.
  219.  * If pName is NULL, the array is simply extended by a NULL pointer.
  220.  */
  221.  
  222. {
  223.   char ** pStrs;
  224.   assert(pArray->size <= pArray->alloc);
  225.   if (pArray->size+1 > pArray->alloc)
  226.   {
  227.     pStrs = (char **)realloc(pArray->strs, sizeof(char *)*(pArray->alloc+4));
  228.     if (!pStrs)
  229.       return 1;
  230.     pArray->strs = pStrs;
  231.     pArray->alloc += 4;
  232.   }
  233.   else
  234.     pStrs = pArray->strs;
  235.   if (pName)
  236.   {
  237.     pStrs[pArray->size] = strdup(pName);
  238.     if (!pStrs[pArray->size])
  239.       return 1;
  240.   }
  241.   else
  242.     pStrs[pArray->size] = NULL;
  243.   pArray->size++;
  244.   return 0;
  245. }
  246.  
  247. /*-------------------------------------------------------------------------*/
  248. static int
  249. array_addlist (SArray *pArray, int count, char ** pList)
  250.  
  251. /* Add the <count> string pointers from <pList> to string array <pArray>.
  252.  * pList may be freed after return, the strings themselves are still
  253.  * referenced (by pArray then).
  254.  * Return 0 on success, non-0 else.
  255.  */
  256.  
  257. {
  258.   char ** pStrs;
  259.   int     i;
  260.  
  261.   assert(pList);
  262.   if (!count)
  263.     return 0;
  264.   assert(pArray->size <= pArray->alloc);
  265.   if (pArray->size+count > pArray->alloc)
  266.   {
  267.     pStrs = (char **)realloc(pArray->strs, sizeof(char *)*(pArray->alloc+count));
  268.     if (!pStrs)
  269.       return 1;
  270.     pArray->strs = pStrs;
  271.     pArray->alloc += count;
  272.   }
  273.   else
  274.     pStrs = pArray->strs;
  275.   for (i = 0; i < count; i++)
  276.     pStrs[pArray->size++] = pList[i];
  277.   return 0;
  278. }
  279.  
  280. /*-------------------------------------------------------------------------*/
  281. static int
  282. add_expfile (SArray *pArray, char * pName)
  283.  
  284. /* Glob filename <*pName> and add the filenames to string array <pArray>.
  285.  * Return 0 on success, non-0 else.
  286.  *
  287.  * The function uses DICE' supplied function expand_args() which does not
  288.  * implement all possible wildcard patterns.
  289.  */
  290.  
  291. {
  292.   char  * argv[] = { NULL, pName, NULL };
  293.   int     argc = 2;
  294.   char ** xargv;
  295.   int     xargc;
  296.   int     rc;
  297.  
  298.   if (expand_args(argc, argv, &xargc, &xargv))
  299.   {
  300.     printf("%s: Error expanding %s\n", aPgmName, pName);
  301.     set_rc(RETURN_ERROR, 1);
  302.   }
  303.   assert(xargc > 1);
  304.  
  305.   rc = 0;
  306.   if (xargc > 1)
  307.   {
  308.     rc = array_addlist(pArray, xargc-1, xargv+1);
  309.     if (rc)
  310.     {
  311.       while (--xargc > 0)
  312.         if (xargv[xargc])
  313.           free(xargv[xargc]);
  314.     }
  315.     free(xargv);
  316.   }
  317.  
  318.   return rc;
  319. }
  320.  
  321. /*-------------------------------------------------------------------------*/
  322. static void
  323. getargs (void)
  324.  
  325. /* Get the arguments from the commandline.
  326.  * Unfortunately we have to emulate ReadArgs() as we have several /M values
  327.  * in our template.
  328.  */
  329.  
  330. {
  331.   int  i;                 /* all purpose */
  332.  
  333.   #define BUFSIZE 1024
  334.   char aBuffer[BUFSIZE];  /* Argument buffer */
  335.   char aArgBuf[BUFSIZE];  /* Source buffer for separator less arguments */
  336.   long item, arg;         /* Result from ReadItem(), FindArg() */
  337.   struct CSource aArgSrc; /* For postponed arguments */
  338.  
  339.   enum {
  340.     NoArg, QuesFound, OtherArg, QuesPending
  341.   } eHelp;
  342.   enum {
  343.     Standard, ParseMake, ParseIncl, ParseExcept, ParseSuffix, ParseObjpat
  344.   } eMulti;
  345.  
  346.   /* General command template */
  347.   char * sTemplate
  348.     = "-F=MAKE/K,-I=INCLUDE/K,-X=EXCEPT/K,-S=SUFFIX/K,-P=OBJPAT/K,-V=VERBOSE/S,FILES/M";
  349.   #define TEMP_MAKE    0
  350.   #define TEMP_INCLUDE 1
  351.   #define TEMP_EXCEPT  2
  352.   #define TEMP_SUFFIX  3
  353.   #define TEMP_PATTERN 4
  354.   #define TEMP_VERBOSE 5
  355.   #define TEMP_FILES   6
  356.  
  357.   /* Options which allow for no separator */
  358.   char * sAbbrev
  359.     = "-F/K,-I/K,-X/K,-S/K,-P/K";
  360.   #define ABBREV_MAKE    0
  361.   #define ABBREV_INCLUDE 1
  362.   #define ABBREV_EXCEPT  2
  363.   #define ABBREV_SUFFIX  3
  364.   #define ABBREV_PATTERN 4
  365.  
  366.   /* Translation table abbrev indices to template indices */
  367.   int aA2T[] = { TEMP_MAKE, TEMP_INCLUDE, TEMP_EXCEPT, TEMP_SUFFIX, TEMP_PATTERN };
  368.  
  369.   eHelp = NoArg;
  370.   eMulti = Standard;
  371.   aArgSrc.CS_Buffer = NULL;
  372.   while(1)
  373.   {
  374.     if (eHelp == QuesPending)
  375.     {
  376.       aBuffer[0] = '?';
  377.       aBuffer[1] = '\0';
  378.       item = ITEM_UNQUOTED;
  379.       eHelp = OtherArg;
  380.     }
  381.     else
  382.     {
  383.       aBuffer[0] = '\0';
  384.       item = ReadItem(aBuffer, BUFSIZE, aArgSrc.CS_Buffer ? &aArgSrc : NULL);
  385.     }
  386.  
  387.     if (ITEM_EQUAL == item)
  388.       item = ITEM_UNQUOTED;
  389.     if (ITEM_ERROR == item)
  390.       exit_doserr(RETURN_ERROR);
  391.  
  392.     if (ITEM_NOTHING == item)
  393.     {
  394.       if (!aArgSrc.CS_Buffer && eHelp != QuesFound)
  395.         break; /* outer while(1) */
  396.       if (aArgSrc.CS_Buffer)
  397.         aArgSrc.CS_Buffer = NULL;
  398.       else
  399.       {
  400.         FGetC(Input()); /* re-read newline */
  401.         Write(Output(), sTemplate, strlen(sTemplate));
  402.         Write(Output(), ": ", 2);
  403.         eHelp = NoArg;
  404.         eMulti = Standard;
  405.       }
  406.       continue;
  407.     }
  408.  
  409.     if (eHelp == NoArg && eMulti == Standard && !strcmp(aBuffer, "?"))
  410.     {
  411.       eHelp = QuesFound;
  412.       continue;
  413.     }
  414.  
  415.     /* At this point, we have an arg beside '?' so mark the '?'
  416.      * for reinsertion
  417.      */
  418.     if (eHelp == QuesFound)
  419.     {
  420.       eHelp = QuesPending;
  421.     }
  422.  
  423.     /* Check if the argument is a keyword */
  424.     arg = -1;
  425.     if (ITEM_UNQUOTED == item && !aArgSrc.CS_Buffer)
  426.     {
  427.       /* Shortcuts need no separator */
  428.       if (aBuffer[0] == '-' && aBuffer[1] != '\0' && aBuffer[2] != '\0')
  429.       {
  430.         char aTmp[3] = { '-', aBuffer[1], '\0' };
  431.         arg = FindArg(sAbbrev, aTmp);
  432.         if (arg != -1)
  433.         {
  434.           int len;
  435.           arg = aA2T[arg];
  436.           strcpy(aArgBuf, aBuffer+2);
  437.           len = strlen(aArgBuf);
  438.           aArgBuf[len] = '\n';   /* ReadItem() needs this as terminator */
  439.           aArgBuf[len+1] = '\0';
  440.           aBuffer[2] = '\0';
  441.           aArgSrc.CS_Buffer = aArgBuf;
  442.           aArgSrc.CS_Length = len+1;
  443.           aArgSrc.CS_CurChr = 0;
  444.         }
  445.       }
  446.       if (arg == -1)
  447.         arg = FindArg(sTemplate, aBuffer);
  448.     }
  449.     /* arg == -1: aBuffer is an argument
  450.      * arg != -1: bufindex == 0: aBuffer is keyword
  451.      */
  452.  
  453.     /* Evaluate keyword if any */
  454.     switch(arg)
  455.     {
  456.     case TEMP_MAKE:
  457.       eMulti = ParseMake;
  458.       break;
  459.     case TEMP_INCLUDE:
  460.       eMulti = ParseIncl;
  461.       break;
  462.     case TEMP_EXCEPT:
  463.       eMulti = ParseExcept;
  464.       break;
  465.     case TEMP_SUFFIX:
  466.       eMulti = ParseSuffix;
  467.       break;
  468.     case TEMP_PATTERN:
  469.       eMulti = ParseObjpat;
  470.       break;
  471.     case TEMP_VERBOSE:
  472.       bVerbose = 1;
  473.       break;
  474.     default:
  475.       assert(arg == -1);
  476.       break;
  477.     }
  478.  
  479.     if (arg != -1)
  480.       continue; /* of while(1) */
  481.  
  482.     /* Assign argument value (if any) */
  483.     switch (eMulti)
  484.     {
  485.     case Standard:
  486.       if (ITEM_QUOTED == item)
  487.         i = array_addfile(&aFiles, aBuffer);
  488.       else
  489.         i = add_expfile(&aFiles, aBuffer);
  490.       if (i)
  491.         exit_nomem(RETURN_FAIL);
  492.       break;
  493.  
  494.     case ParseMake:
  495.       if (sMake)
  496.         free(sMake);
  497.       sMake = strdup(aBuffer);
  498.       if (!sMake)
  499.         exit_nomem(RETURN_FAIL);
  500.       break;
  501.  
  502.     case ParseExcept:
  503.       if (ITEM_QUOTED == item)
  504.         i = array_addfile(&aAvoid, aBuffer);
  505.       else
  506.         i = add_expfile(&aAvoid, aBuffer);
  507.       if (i)
  508.         exit_nomem(RETURN_FAIL);
  509.       break;
  510.  
  511.     case ParseIncl:
  512.       {
  513.         char * pSym, * pMark;
  514.  
  515.         /* Allow for <path>::<symbol> notation */
  516.         pSym = NULL;
  517.         pMark = aBuffer+strlen(aBuffer);
  518.         if (pMark != aBuffer)
  519.         {
  520.           pMark--;
  521.           while (!pSym && pMark >= aBuffer+1)
  522.           {
  523.             if (':' != *pMark)
  524.             {
  525.               pMark--;
  526.               continue;
  527.             }
  528.             if (':' != *(pMark-1))
  529.             {
  530.               pMark -= 2;
  531.               continue;
  532.             }
  533.             pSym = pMark+1;
  534.             *(pMark-1) = '\0';
  535.           }
  536.         }
  537.         if (pSym && !strlen(pSym))
  538.           pSym = NULL;
  539.         i = array_addfile(&aSymbol, pSym);
  540.         if (i)
  541.           exit_nomem(RETURN_FAIL);
  542.  
  543.         /* Make sure <path> ends in a ':' or '/' */
  544.         pMark = aBuffer+strlen(aBuffer);
  545.         if (pMark > aBuffer && ':' != *(pMark-1) && '/' != *(pMark-1))
  546.         {
  547.           *pMark = '/';
  548.           *(pMark+1) = '\0';
  549.         }
  550.         i = array_addfile(&aIncl, aBuffer);
  551.         if (i)
  552.           exit_nomem(RETURN_FAIL);
  553.       }
  554.       break;
  555.  
  556.     case ParseSuffix:
  557.     case ParseObjpat:
  558.       {
  559.         char * pMark, *pOsfix;
  560.  
  561.         /* Allow for <src_suffix>:<obj_suffix> notation */
  562.         pOsfix = NULL;
  563.         pMark = aBuffer+strlen(aBuffer);
  564.         if (pMark != aBuffer)
  565.         {
  566.           pMark--;
  567.           while (!pOsfix && pMark >= aBuffer)
  568.           {
  569.             if (':' != *pMark)
  570.             {
  571.               pMark--;
  572.               continue;
  573.             }
  574.             pOsfix = pMark+1;
  575.             *pMark = '\0';
  576.           }
  577.         }
  578.         if (pOsfix && !strlen(pOsfix))
  579.           pOsfix = NULL;
  580.  
  581.         if (ParseObjpat == eMulti && !pOsfix)
  582.         {
  583.           printf("%s: Object pattern missing in argument.\n", aPgmName);
  584.           set_rc(RETURN_WARN, 0);
  585.           break;
  586.         }
  587.  
  588.         /* :<obj_suffix> alone defines default object suffix */
  589.         if (pOsfix && !strlen(aBuffer))
  590.         {
  591.           if (sObjExt)
  592.             free(sObjExt);
  593.           sObjExt = strdup(pOsfix);
  594.           if (!sObjExt)
  595.             exit_nomem(RETURN_FAIL);
  596.         }
  597.         else
  598.         {
  599.           char * pSfix;
  600.  
  601.           /* Allow for <sfix1>,<sfix2>,...,<sfixn> for source suffixes */
  602.           for ( pSfix = aBuffer
  603.               ; pMark = strchr(pSfix, ',')
  604.               ; pSfix = pMark+1
  605.               )
  606.           {
  607.             *pMark = '\0';
  608.             if (strlen(pSfix))
  609.             {
  610.               if (   array_addfile(&aSrcExt, pSfix)
  611.                   || (ParseSuffix == eMulti ? array_addfile(&aObjExt, pOsfix)
  612.                                             : array_addfile(&aObjPat, pOsfix)
  613.                      )
  614.                  )
  615.                 exit_nomem(RETURN_FAIL);
  616.             }
  617.           }
  618.           if (strlen(pSfix))
  619.           {
  620.             if (   array_addfile(&aSrcExt, pSfix)
  621.                 || (ParseSuffix == eMulti ? array_addfile(&aObjExt, pOsfix)
  622.                                           : array_addfile(&aObjPat, pOsfix)
  623.                    )
  624.                )
  625.               exit_nomem(RETURN_FAIL);
  626.           }
  627.         }
  628.       }
  629.       break;
  630.  
  631.     default:
  632.       assert(0);
  633.     }
  634.  
  635.     eMulti = Standard;
  636.   } /* while(1) */
  637.  
  638.   #undef BUFSIZE
  639.   #undef TEMP_MAKE
  640.   #undef TEMP_INCLUDE
  641.   #undef TEMP_EXCEPT
  642.   #undef TEMP_SUFFIX
  643.   #undef TEMP_PATTERN
  644.   #undef TEMP_VERBOSE
  645.   #undef TEMP_FILES
  646.   #undef ABBREV_MAKE
  647.   #undef ABBREV_INCLUDE
  648.   #undef ABBREV_EXCEPT
  649.   #undef ABBREV_SUFFIX
  650.   #undef ABBREV_PATTERN
  651. }
  652.  
  653. /*-------------------------------------------------------------------------*/
  654. static int
  655. readfiles (void)
  656.  
  657. /* Read and analyse all files.
  658.  * If a file can't be read, print a message.
  659.  * Return 0 if all went well, RETURN_WARN if one of the files could not be
  660.  * found, RETURN_ERROR if one of the files could not be read properly.
  661.  */
  662.  
  663. {
  664.   int           rc;       /* Return value */
  665.   struct stat   aStat;    /* buffer for stat() */
  666.   Node        * pNode;    /* Node of the file under examination */
  667.   int           srcRead;  /* Number of source files read */
  668.   int           index;    /* index in the aIncl array */
  669.   char          aName[FILENAME_MAX+1];
  670.   int           i;
  671.   const char  * pName;    /* Includefile name returned by reader */
  672.  
  673.   rc = 0;
  674.   srcRead = 0;
  675.   aName[FILENAME_MAX] = '\0';
  676.  
  677.   while (pNode = nodes_todo())
  678.   {
  679.     /* Search the correct directory to read from */
  680.     index = -1;
  681.     pNode->iInclude = 0;
  682.     strcpy(aName, pNode->pName);
  683.     i = stat(aName, &aStat);
  684.     if (i && !(pNode->flags & NODE_SOURCE))
  685.     {
  686.       for (index = 0; i && index < aIncl.size; index++)
  687.       {
  688.         strcpy(aName, aIncl.strs[index]);
  689.         strcat(aName, pNode->pName);
  690.         assert(aName[FILENAME_MAX] == '\0');
  691.         i = stat(aName, &aStat);
  692.       }
  693.       if (!i)
  694.         pNode->iInclude = index;
  695.     }
  696.     if (i || !reader_open(aName))
  697.     {
  698.       if (!i)
  699.         perror("mkdepend");
  700.       if (rc < RETURN_ERROR)
  701.         rc = RETURN_WARN;
  702.       printf("%s: Warning: Cant't read '%s'.\n", aPgmName, aName);
  703.       continue;
  704.     }
  705.     if (bVerbose)
  706.     {
  707.       printf(" reading %-65s\r", aName); fflush(stdout);
  708.     }
  709.     while (pName = reader_get())
  710.     {
  711.       if (nodes_depend(pNode, pName))
  712.       {
  713.         if (bVerbose)
  714.           printf("%+-78s\r", "");
  715.         reader_close();
  716.         exit_nomem(RETURN_FAIL);
  717.       }
  718.     }
  719.     if (bVerbose)
  720.       printf("%+-78s\r", "");
  721.     if (!reader_eof() || reader_close())
  722.     {
  723.       perror("mkdepend");
  724.       printf("%s: Error reading '%s'\n", aPgmName, aName);
  725.       rc = RETURN_ERROR;
  726.     }
  727.     else if (pNode->flags & NODE_SOURCE)
  728.     {
  729.       srcRead++;
  730.     }
  731.   } /* while (nodes_todo()) */
  732.   if (!srcRead)
  733.   {
  734.     printf("%s: No source file read.\n", aPgmName);
  735.     rc = RETURN_ERROR;
  736.   }
  737.   if (bVerbose)
  738.     fflush(stdout);
  739.   return rc;
  740. }
  741.  
  742. /*-------------------------------------------------------------------------*/
  743. static void
  744. make_objname ( char *pBuf, const char *pName, int slen
  745.              , const char * pObjExt, const char *pObjPat
  746.              )
  747.  
  748. /* Construct the name of the dependency target.
  749.  *
  750.  *   pBuf   : Buffer to construct the name in.
  751.  *   pName  : Name of the sourcefile.
  752.  *   slen   : Length of the sourcefile suffix.
  753.  *   pObjExt: Object extensions for this sourcefile, may be NULL.
  754.  *   pObjPat: Object pattern for this sourcefile, may be NULL.
  755.  *
  756.  * If pObjPat is not NULL, the pattern is used to construct the name.
  757.  * If pObjPat is NULL, the pObjExt string is appended to the sourcefile
  758.  * name (minus its source suffix) to construct the name. If pObjExt is
  759.  * NULL, the default object extension is used.
  760.  */
  761.  
  762. {
  763.   int nlen, plen;
  764.   char * pBasename;
  765.   char * pSrc, *pDst, *pMark, ch;
  766.   short flags;
  767.   long  number;
  768.  
  769. #define GOT_MINUS   (1<<0)
  770. #define GOT_ANGLE   (1<<1)
  771. #define GOT_NUMBER  (1<<2)
  772. #define NOT_DONE    (1<<3)
  773. #define NO_PATTERN  (1<<4)
  774.  
  775.   nlen = strlen(pName)-slen;
  776.   if (!pObjPat)
  777.   {
  778.     strcpy(pBuf, pName);
  779.     if (pObjExt)
  780.       strcpy(pBuf+nlen, pObjExt);
  781.     else
  782.       strcpy(pBuf+nlen, sObjExt);
  783.     return;
  784.   }
  785.   pBasename = FilePart(pName);
  786.   plen = pBasename-pName;
  787.   pSrc = pObjPat;
  788.   pDst = pBuf;
  789.   while ('\0' != (ch = *pSrc++))
  790.   {
  791.     if (ch != '%')
  792.     {
  793.       *pDst++ = ch;
  794.       continue;
  795.     }
  796.  
  797.     pMark = pSrc;
  798.     flags = 0;
  799.     do
  800.     {
  801.       ch = *pSrc++;
  802.       switch(ch)
  803.       {
  804.       case '-':
  805.         if (flags & (GOT_MINUS|GOT_ANGLE|GOT_NUMBER))
  806.           flags = NO_PATTERN;
  807.         else
  808.           flags |= GOT_MINUS|NOT_DONE;
  809.         break;
  810.  
  811.       case '<':
  812.         if (flags & (GOT_ANGLE|GOT_NUMBER))
  813.           flags = NO_PATTERN;
  814.         else
  815.           flags |= GOT_ANGLE|NOT_DONE;
  816.         break;
  817.  
  818.       case '0': case '1': case '2': case '3': case '4':
  819.       case '5': case '6': case '7': case '8': case '9':
  820.         if (flags & GOT_NUMBER)
  821.           flags = NO_PATTERN;
  822.         else
  823.         {
  824.           char * pTail;
  825.  
  826.           number = strtol(pSrc-1, &pTail, 10);
  827.           pSrc = pTail;
  828.           flags |= GOT_NUMBER|NOT_DONE;
  829.         }
  830.         break;
  831.  
  832.       case 's':
  833.         strncpy(pDst, pName, nlen);
  834.         pDst += nlen;
  835.         flags = 0;
  836.         break;
  837.  
  838.       case 'p':
  839.         if (pName != pBasename
  840.         && (!(flags & GOT_MINUS) || (flags & GOT_NUMBER))
  841.         )
  842.         {
  843.           char * cp;
  844.           size_t cplen;
  845.  
  846.           cp = pName;
  847.           cplen = plen;
  848.           if (flags & GOT_NUMBER)
  849.           {
  850.             if (flags & GOT_ANGLE)
  851.             {
  852.               cp = pName+plen;
  853.               number++;
  854.               while (number)
  855.               {
  856.                 --cp;
  857.                 if (*cp == '/' || *cp == ':')
  858.                 {
  859.                   number--;
  860.                   if (!number)
  861.                     cp++;
  862.                 }
  863.                 if (cp == pName)
  864.                   break;
  865.               }
  866.             }
  867.             else
  868.             {
  869.               cp = pName;
  870.               while (number && cp != pBasename)
  871.               {
  872.                 if (*cp == '/' || *cp == ':')
  873.                 {
  874.                   number--;
  875.                 }
  876.                 cp++;
  877.               }
  878.             }
  879.             /* cp now points to the character after the
  880.              * determined path part.
  881.              */
  882.  
  883.             if (flags & GOT_MINUS)
  884.             {
  885.               cplen = cp - pName;
  886.               cp = pName;
  887.             }
  888.             else
  889.               cplen = plen - (cp-pName);
  890.           }
  891.           if (cplen)
  892.           {
  893.             strncpy(pDst, cp, cplen);
  894.             pDst += cplen;
  895.           }
  896.         }
  897.         flags = 0;
  898.         break;
  899.  
  900.       case 'n':
  901.         strncpy(pDst, pBasename, nlen-plen);
  902.         pDst += nlen-plen;
  903.         flags = 0;
  904.         break;
  905.  
  906.       case '%':
  907.         *pDst++ = '%';
  908.         flags = 0;
  909.         break;
  910.  
  911.       default:
  912.         flags = NO_PATTERN;
  913.         break;
  914.       }
  915.     }
  916.     while (flags & NOT_DONE);
  917.     if (flags & NO_PATTERN)
  918.       pSrc = pMark; /* to be read again as normal text */
  919.   }
  920.   *pDst = '\0';
  921.  
  922. #undef GOT_MINUS
  923. #undef GOT_ANGLE
  924. #undef GOT_NUMBER
  925. #undef NOT_DONE
  926. #undef NO_PATTERN
  927. }
  928.  
  929. /*-------------------------------------------------------------------------*/
  930. static int
  931. output (void)
  932.  
  933. /* Output the collected dependencies into the Makefile.
  934.  * Return 0 on success, RETURN_WARN on a mild error, RETURN_ERROR on a
  935.  * severe error.
  936.  */
  937.  
  938. {
  939.   int       rc;
  940.   char    * pBackup;  /* Name of the Makefilebackup */
  941.   Node    * pNode;
  942.  
  943.   pBackup = NULL;
  944.  
  945.   /* Rename old Makefile if necessary */
  946.   if (bMakeExists)
  947.   {
  948.     pBackup = (char *)malloc(strlen(sMake)+4);
  949.     strcpy(pBackup, sMake);
  950.     strcat(pBackup, ".bak");
  951.     remove(pBackup);
  952.     if (rename(sMake, pBackup))
  953.     {
  954.       perror("mkdepend");
  955.       printf("%s: Can't rename '%s' to '%s'.\n", aPgmName, sMake, pBackup);
  956.       free(pBackup);
  957.       return RETURN_ERROR;
  958.     }
  959.   }
  960.  
  961.   rc = RETURN_OK;
  962.   do
  963.   {
  964.     /* Open files */
  965.     if (reader_openrw(pBackup, sMake))
  966.     {
  967.       perror("mkdepend");
  968.       printf("%s: Can't write '%s'\n", aPgmName, sMake);
  969.       rc = RETURN_ERROR;
  970.       break;
  971.     }
  972.  
  973.     if (bVerbose)
  974.     {
  975.       printf(" %s '%s'\r", bMakeExists ? "updating" : "creating", sMake); fflush(stdout);
  976.     }
  977.  
  978.     /* Copy the Makefile up to the tagline */
  979.     if (reader_copymake("# --- DO NOT MODIFY THIS LINE -- AUTO-DEPENDS FOLLOW ---\n"))
  980.     {
  981.       int i = errno;
  982.       if (bVerbose)
  983.         printf("%+-78s\r", "");
  984.       errno = i;
  985.       perror("mkdepend");
  986.       printf("%s: Error copying '%s' to '%s'.\n", aPgmName, pBackup, sMake);
  987.       rc = RETURN_ERROR;
  988.       break;
  989.     }
  990.  
  991.     /* Walk and output the dependencies */
  992.     nodes_initwalk();
  993.     while (rc != RETURN_ERROR && (pNode = nodes_inorder()))
  994.     {
  995.       if ((pNode->flags & (NODE_SOURCE|NODE_AVOID)) == NODE_SOURCE)
  996.       {
  997.         Node    * pRNode;
  998.         NodeRef * pList, * pRef;
  999.         int       suffix;         /* Suffix index */
  1000.         int       slen;           /* Linelen so far */
  1001.         int       len;
  1002.         char      aObjname[FILENAME_MAX+1];
  1003.  
  1004.         aObjname[FILENAME_MAX] = '\0';
  1005.  
  1006.         pList = nodes_deplist(pNode);
  1007.         assert(pList);
  1008.         pRef = pList;
  1009.  
  1010.         /* Check for a given suffix.
  1011.          * Search backwards in case later definitions overwrote
  1012.          * earlier ones.
  1013.          */
  1014.         slen = strlen(pNode->pName);
  1015.         for (suffix = aSrcExt.size-1; suffix >= 0; suffix--)
  1016.         {
  1017.           len = strlen(aSrcExt.strs[suffix]);
  1018.           if (!strcmp(pNode->pName+slen-len, aSrcExt.strs[suffix]))
  1019.             break;
  1020.         }
  1021.  
  1022.         /* Construct the name of the dependency target and write it */
  1023.         if (suffix >= 0)
  1024.         {
  1025.           make_objname( aObjname, pNode->pName, len
  1026.                       , aObjExt.size ? aObjExt.strs[suffix] : NULL
  1027.                       , aObjPat.size ? aObjPat.strs[suffix] : NULL
  1028.                       );
  1029.           assert(aObjname[FILENAME_MAX] == '\0');
  1030.           if (reader_write(aObjname))
  1031.           {
  1032.             rc = RETURN_ERROR;
  1033.             break; /* outer while */
  1034.           }
  1035.           slen = strlen(aObjname);
  1036.         }
  1037.         else
  1038.         {
  1039.           if (reader_write(pNode->pName))
  1040.           {
  1041.             rc = RETURN_ERROR;
  1042.             break; /* outer while */
  1043.           }
  1044.           pRef = pRef->pNext;
  1045.         }
  1046.  
  1047.         if (reader_write(" : "))
  1048.         {
  1049.           rc = RETURN_ERROR;
  1050.           break; /* outer while */
  1051.         }
  1052.         slen += 3;
  1053.  
  1054.         for ( ; rc != RETURN_ERROR && pRef; pRef = pRef->pNext)
  1055.         {
  1056.           pRNode = pRef->pNode;
  1057.           /* Construct the name of the dependee */
  1058.           aObjname[0] = ' ';
  1059.           aObjname[1] = '\0';
  1060.           if (pRNode->iInclude)
  1061.           {
  1062.             if (aSymbol.strs[pRNode->iInclude-1])
  1063.               strcat(aObjname, aSymbol.strs[pRNode->iInclude-1]);
  1064.             else
  1065.               strcat(aObjname, aIncl.strs[pRNode->iInclude-1]);
  1066.             strcat(aObjname, pRNode->pName);
  1067.           }
  1068.           else
  1069.           {
  1070.             strcat(aObjname, pRNode->pName);
  1071.           }
  1072.           assert(aObjname[FILENAME_MAX] == '\0');
  1073.           len = strlen(aObjname);
  1074.  
  1075.           /* Fit it into the line */
  1076.           if (slen > 0)
  1077.           {
  1078.             if (slen+len > 75)
  1079.             {
  1080.               if (reader_writen(" \\\n", 3))
  1081.               {
  1082.                 rc = RETURN_ERROR;
  1083.                 break; /* inner while */
  1084.               }
  1085.               slen = 0;
  1086.             }
  1087.           }
  1088.           if (!slen)
  1089.           {
  1090.             if (reader_writen("   ", 3))
  1091.             {
  1092.               rc = RETURN_ERROR;
  1093.               break; /* inner while */
  1094.             }
  1095.             slen = 3;
  1096.           }
  1097.           if (reader_writen(aObjname, len))
  1098.           {
  1099.             rc = RETURN_ERROR;
  1100.             break; /* inner while */
  1101.           }
  1102.           slen += len;
  1103.         } /* for () */
  1104.         nodes_freelist(pList);
  1105.         if (slen && reader_writen("\n\n", 2))
  1106.         {
  1107.           rc = RETURN_ERROR;
  1108.           break; /* outer while */
  1109.         }
  1110.       } /* if (source node) */
  1111.     }  /* while (treewalk */
  1112.  
  1113.     if (rc == RETURN_ERROR)
  1114.     {
  1115.       int i = errno;
  1116.       if (bVerbose)
  1117.         printf("%+-78s\r", "");
  1118.       errno = i;
  1119.       perror("mkdepend");
  1120.       printf("%s: Error writing '%s'.\n", aPgmName, sMake);
  1121.       rc = RETURN_ERROR;
  1122.       break;
  1123.     }
  1124.  
  1125.     if (reader_copymake2("# --- DO NOT MODIFY THIS LINE -- AUTO-DEPENDS PRECEDE ---\n"))
  1126.     {
  1127.       int i = errno;
  1128.       if (bVerbose)
  1129.         printf("%+-78s\r", "");
  1130.       errno = i;
  1131.       perror("mkdepend");
  1132.       printf("%s: Error copying '%s' to '%s'.\n", aPgmName, pBackup, sMake);
  1133.       rc = RETURN_ERROR;
  1134.       break;
  1135.     }
  1136.     /* Finish up */
  1137.     if (bVerbose)
  1138.       printf("%+-78s\r", "");
  1139.  
  1140.     if (reader_close())
  1141.     {
  1142.       perror("mkdepend");
  1143.       printf("%s: Error writing '%s'.\n", aPgmName, sMake);
  1144.       rc = RETURN_ERROR;
  1145.       break;
  1146.     }
  1147.  
  1148.     if (bMakeExists && chmod(sMake, aMakeStat.st_mode))
  1149.     {
  1150.       /* perror("mkdepend"); */
  1151.       printf("%s: Warning: Can't update mode of '%s'.\n", aPgmName, sMake);
  1152.       rc = RETURN_WARN;
  1153.     }
  1154.  
  1155.     if (pBackup && remove(pBackup))
  1156.     {
  1157.       perror("mkdepend");
  1158.       printf("%s: Warning: Can't remove backup '%s'.\n", aPgmName, pBackup);
  1159.       rc = RETURN_WARN;
  1160.       break;
  1161.     }
  1162.  
  1163.   } while(0);
  1164.  
  1165.   /* Error cleanup */
  1166.   if (rc == RETURN_ERROR)
  1167.   {
  1168.     reader_close();
  1169.     remove(sMake);
  1170.     if (pBackup && rename(pBackup, sMake))
  1171.     {
  1172.       perror("mkdepend");
  1173.       printf("%s: Can't restore '%s' from backup '%s'\n", aPgmName, sMake, pBackup);
  1174.     }
  1175.   }
  1176.  
  1177.   if (bVerbose && rc != RETURN_ERROR)
  1178.     printf("%+-78s\r", "");
  1179.  
  1180.   if (pBackup)
  1181.     free(pBackup);
  1182.  
  1183.   return rc;
  1184. }
  1185.  
  1186. /*-------------------------------------------------------------------------*/
  1187. int main (int argc, char *argv[])
  1188.  
  1189. {
  1190.   int i;
  1191.  
  1192.   check_os2();
  1193.  
  1194.   /* Determine the program executables name */
  1195.   aPgmName = strdup(FilePart(argv[0]));
  1196.   if (!aPgmName)
  1197.     aPgmName = "mkdepend";
  1198.  
  1199.   CheckStacksize(10240);
  1200.  
  1201.   reader_init();
  1202.  
  1203.   /* Get arguments, set up defaults */
  1204.   getargs();
  1205.   if (!aFiles.size)
  1206.   {
  1207.     if (add_expfile(&aFiles, "#?.c"))
  1208.       exit_nomem(RETURN_FAIL);
  1209.   }
  1210.   if (!sObjExt)
  1211.     sObjExt = ".o";
  1212.  
  1213.   if (!aSrcExt.size)
  1214.   {
  1215.     if (array_addfile(&aSrcExt, ".c") || array_addfile(&aObjExt, NULL))
  1216.       exit_nomem(RETURN_FAIL);
  1217.   }
  1218.  
  1219.   if (bVerbose)
  1220.   {
  1221.     printf("MkDepend %s (%s) -- Make Dependency Generator\n", VERSION, __DATE__);
  1222.     puts("Copyright © 1995 Lars Düning.");
  1223.     putchar('\n');
  1224.   }
  1225.  
  1226.   /* Look for the Makefile to modify */
  1227.   if (sMake)
  1228.   {
  1229.     bMakeExists = !stat(sMake, &aMakeStat);
  1230.   }
  1231.   else
  1232.   {
  1233.     sMake = "Makefile";
  1234.     bMakeExists = !stat(sMake, &aMakeStat);
  1235.     if (!bMakeExists)
  1236.     {
  1237.       sMake = "Makefile.mk";
  1238.       bMakeExists = !stat(sMake, &aMakeStat);
  1239.     }
  1240.     if (!bMakeExists)
  1241.     {
  1242.       sMake = "DMakefile";
  1243.       bMakeExists = !stat(sMake, &aMakeStat);
  1244.     }
  1245.     if (!bMakeExists)
  1246.     {
  1247.       sMake = "SMakefile";
  1248.       bMakeExists = !stat(sMake, &aMakeStat);
  1249.     }
  1250.     if (!bMakeExists)
  1251.       sMake = "Makefile";
  1252.   }
  1253.  
  1254.   /* Add the source files to the tree */
  1255.   if (!aFiles.size)
  1256.   {
  1257.     printf("%s: No files given.\n", aPgmName);
  1258.     set_rc(RETURN_WARN, 1);
  1259.   }
  1260.   for (i = 0; i < aFiles.size; i++)
  1261.   {
  1262.     if (nodes_addsource(aFiles.strs[i], 0))
  1263.       exit_nomem(RETURN_FAIL);
  1264.   }
  1265.  
  1266.   /* Mark the exceptional files */
  1267.   for (i = 0; i < aAvoid.size; i++)
  1268.   {
  1269.     if (nodes_addsource(aAvoid.strs[i], 1))
  1270.       exit_nomem(RETURN_FAIL);
  1271.   }
  1272.  
  1273.   /* Read and analyse all those files */
  1274.   set_rc(readfiles(), 0);
  1275.  
  1276.   if (returncode < RETURN_ERROR)
  1277.     set_rc(output(), 0);
  1278.  
  1279.   if (returncode < RETURN_ERROR && bVerbose)
  1280.     printf("%s '%s'.\n", bMakeExists ? "Updated" : "Created", sMake);
  1281.  
  1282.   return returncode;
  1283. }
  1284.  
  1285. /***************************************************************************/
  1286.